package com.su.fileupload.service.impl;

import cn.hutool.core.io.FileUtil;
import com.su.fileupload.entity.SysChunk;
import com.su.fileupload.entity.SysFileList;
import com.su.fileupload.service.ISysChunkService;
import com.su.fileupload.service.ISysFileListService;
import com.su.fileupload.service.ISysFileService;
import com.su.fileupload.vo.request.FileChunkRequest;
import com.su.fileupload.vo.response.FileChunkCheckResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author xysusj
 */
@Service
public class SysFileServiceImpl implements ISysFileService {

    @Value("${file-upload.path}")
    private String uploadPath;

    @Value("${file-upload.chunk-path}")
    private String chunkPath;

    @Resource
    private ISysChunkService sysChunkService;

    @Resource
    private ISysFileListService sysFileListService;

    @Override
    public FileChunkCheckResponse upload(FileChunkRequest fileChunkRequest) throws IOException {
        String path = chunkPath + File.separator + fileChunkRequest.getIdentifier();
        boolean exist = FileUtil.exist(path);
        if (!exist) {
            // 创建文件夹
            FileUtil.mkdir(path);
        }
        // 保存文件
        FileUtil.writeBytes(fileChunkRequest.getFile().getBytes(), path + File.separator + fileChunkRequest.getChunkNumber());
        // 保存分片信息
        SysChunk sysChunk = new SysChunk();
        sysChunk.setChunkNumber(fileChunkRequest.getChunkNumber());
        sysChunk.setChunkSize(fileChunkRequest.getChunkSize());
        sysChunk.setCurrentChunkSize(fileChunkRequest.getCurrentChunkSize());
        sysChunk.setFilename(fileChunkRequest.getFilename());
        sysChunk.setIdentifier(fileChunkRequest.getIdentifier());
        sysChunk.setRelativePath(path);
        sysChunk.setTotalChunks(fileChunkRequest.getTotalChunks());
        sysChunk.setTotalSize(fileChunkRequest.getTotalSize());
        sysChunkService.save(sysChunk);
        // 查询所有分块
        List<SysChunk> chunkList = sysChunkService.getChunkList(fileChunkRequest.getIdentifier());
        List<Integer> chunkNumberList = chunkList.stream().mapToInt(SysChunk::getChunkNumber).boxed().collect(Collectors.toList());
        FileChunkCheckResponse response = FileChunkCheckResponse.builder().uploaded(chunkNumberList).build();
        // 是否上传完成
        if (chunkNumberList.size() == fileChunkRequest.getTotalChunks()) {
            response.setNeedMerge(Boolean.TRUE);
        }
        // 是否需要添加当前分块
        return response;
    }

    @Override
    public boolean merge(FileChunkRequest fileChunkRequest) {
        Integer totalChunks = fileChunkRequest.getTotalChunks();
        String chunkFile = chunkPath + File.separator + fileChunkRequest.getIdentifier();
        if (checkChunk(totalChunks, chunkFile)) {
            // 读取所有分片文件
            String file = uploadPath + File.separator + fileChunkRequest.getFilename();
            File chunkFileFolder = new File(chunkFile);
            // 要合并生成的文件
            File mergeFile = new File(file);
            File[] chunks = chunkFileFolder.listFiles();
            // 切片排序
            assert chunks != null;
            List<File> fileList = Arrays.asList(chunks);
            fileList.sort(Comparator.comparingInt((File o) -> Integer.parseInt(o.getName())));
            try {
                RandomAccessFile randomAccessFileWriter = new RandomAccessFile(mergeFile, "rw");
                byte[] bytes = new byte[1024];
                for (File chunk : chunks) {
                    RandomAccessFile randomAccessFileReader = new RandomAccessFile(chunk, "r");
                    int len;
                    while ((len = randomAccessFileReader.read(bytes)) != -1) {
                        randomAccessFileWriter.write(bytes, 0, len);
                    }
                    randomAccessFileReader.close();
                }
                randomAccessFileWriter.close();
            } catch (Exception ignored) {
                return Boolean.FALSE;
            }
            // 删除分片文件夹
            FileUtil.del(chunkFile);
            // 清空分片信息
            sysChunkService.removeByFileIdentifier(fileChunkRequest.getIdentifier());
            // 计算文件总大小

            // 保存文件信息
            SysFileList sysFileList = new SysFileList();
            sysFileList.setFilename(fileChunkRequest.getFilename());
            sysFileList.setIdentifier(fileChunkRequest.getIdentifier());
            sysFileList.setLocation(file);
            sysFileList.setTotalSize(fileChunkRequest.getTotalSize());
            sysFileListService.save(sysFileList);
        }
        return Boolean.TRUE;
    }

    /**
     * 校验分片文件是否存在
     *
     * @param totalChunks 分片总数
     * @param chunkFile   分片文件夹
     * @return
     */
    private boolean checkChunk(Integer totalChunks, String chunkFile) {
        try {
            for (int i = 1; i <= totalChunks + 1; i++) {
                File file = new File(chunkFile + File.separator + i);
                if (!file.exists()) {
                    return Boolean.FALSE;
                }
            }
        } catch (Exception e) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }


}
